package cn.lili.modules.store.serviceimpl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.UserEnums;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.modules.order.order.entity.dto.StoreFlowQueryDTO;
import cn.lili.modules.order.order.entity.enums.FlowTypeEnum;
import cn.lili.modules.order.order.service.StoreFlowService;
import cn.lili.modules.store.entity.dos.Bill;
import cn.lili.modules.store.entity.dto.BillSearchParams;
import cn.lili.modules.store.entity.enums.BillStatusEnum;
import cn.lili.modules.store.entity.vos.BillListVO;
import cn.lili.modules.store.entity.vos.StoreDetailVO;
import cn.lili.modules.store.entity.vos.StoreFlowPayDownloadVO;
import cn.lili.modules.store.entity.vos.StoreFlowRefundDownloadVO;
import cn.lili.modules.store.mapper.BillMapper;
import cn.lili.modules.store.service.BillService;
import cn.lili.modules.store.service.StoreDetailService;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

/**
 * 结算单业务层实现
 *
 * @author Chopper
 * @since 2020/11/17 4:28 下午
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BillServiceImpl extends ServiceImpl<BillMapper, Bill> implements BillService {

	/**
	 * 店铺详情
	 */
	@Autowired
	private StoreDetailService storeDetailService;
	/**
	 * 商家流水
	 */
	@Autowired
	private StoreFlowService storeFlowService;

	@Override
	public void createBill(String storeId, Date startTime, DateTime endTime) {

		// 获取结算店铺
		StoreDetailVO store = storeDetailService.getStoreDetailVO(storeId);
		Bill bill = new Bill();

		// 结算基础信息
		bill.setStartTime(startTime);
		bill.setEndTime(DateUtil.yesterday());
		bill.setBillStatus(BillStatusEnum.OUT.name());
		bill.setStoreId(storeId);
		bill.setStoreName(store.getStoreName());

		// 设置结算信息
		bill.setBankAccountName(store.getSettlementBankAccountName());
		bill.setBankAccountNumber(store.getSettlementBankAccountNum());
		bill.setBankCode(store.getSettlementBankJointName());
		bill.setBankName(store.getSettlementBankBranchName());

		// 店铺结算单号
		bill.setSn(SnowFlake.createStr("B"));

		// 入账结算信息
		Bill orderBill = this.baseMapper.getOrderBill(new QueryWrapper<Bill>().eq("store_id", storeId)
				.eq("flow_type", FlowTypeEnum.PAY.name()).between("create_time", startTime, endTime));
		double orderPrice = 0D;
		if (orderBill != null) {
			bill.setOrderPrice(orderBill.getOrderPrice());
			bill.setCommissionPrice(orderBill.getCommissionPrice());
			bill.setDistributionCommission(orderBill.getDistributionCommission());
			bill.setSiteCouponCommission(orderBill.getSiteCouponCommission());
			bill.setPointSettlementPrice(orderBill.getPointSettlementPrice());
			bill.setKanjiaSettlementPrice(orderBill.getKanjiaSettlementPrice());
			// 入账金额=订单金额
			orderPrice = orderBill.getBillPrice();
		}

		// 退款结算信息
		Bill refundBill = this.baseMapper.getRefundBill(new QueryWrapper<Bill>().eq("store_id", storeId)
				.eq("flow_type", FlowTypeEnum.REFUND.name()).between("create_time", startTime, endTime));
		Double refundPrice = 0D;
		if (refundBill != null) {
			bill.setRefundPrice(refundBill.getRefundPrice());
			bill.setRefundCommissionPrice(refundBill.getRefundCommissionPrice());
			bill.setDistributionRefundCommission(refundBill.getDistributionRefundCommission());
			bill.setSiteCouponRefundCommission(refundBill.getSiteCouponRefundCommission());
			refundPrice = refundBill.getBillPrice();
		}

		// 最终结算金额=入款结算金额-退款结算金额
		Double finalPrice = CurrencyUtil.sub(orderPrice, refundPrice);
		bill.setBillPrice(finalPrice);

		// 添加结算单
		this.save(bill);

	}

	/**
	 * 立即结算
	 *
	 * @param storeId
	 * @param endTime
	 *            结束时间
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void immediatelyBill(String storeId, Long endTime) {

		// Long now = DateUtil.getDateline();
		// //TODO 需要获取真实店铺
		// StoreDetailVO store = new StoreDetailVO();
		// Long startTime = store.getLastBillTime().getTime();
		//
		// store.setLastBillTime(new Date(now));
		//// TODO store.save 保存新的结束时间
		//
		// //TODO 获取结算周期内的结算详情
		// BillDTO billDTO = new BillDTO();
		//
		// //如果没有需要结算单，那么就可以直接返回，也不需要保存新的结算单
		// if (billDTO.getOrderPrice() == 0 && billDTO.getRefundPrice() == 0) {
		// return;
		// }
		//
		// this.createBill(storeId, startTime, endTime);
	}

	@Override
	public IPage<BillListVO> billPage(BillSearchParams billSearchParams) {
		QueryWrapper<BillListVO> queryWrapper = billSearchParams.queryWrapper();
		return this.baseMapper.queryBillPage(PageUtil.initPage(billSearchParams), queryWrapper);
	}

	@Override
	public boolean check(String id) {
		Bill bill = this.getById(id);
		// 判断当前结算单状态为：出账
		if (!bill.getBillStatus().equals(BillStatusEnum.OUT.name())) {
			throw new ServiceException(ResultCode.BILL_CHECK_ERROR);
		}
		// 判断操作人员为商家
		if (!UserContext.getCurrentUser().getRole().equals(UserEnums.STORE)) {
			throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
		}
		LambdaUpdateWrapper<Bill> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
		lambdaUpdateWrapper.eq(Bill::getId, id);
		lambdaUpdateWrapper.set(Bill::getBillStatus, BillStatusEnum.CHECK.name());
		return this.update(lambdaUpdateWrapper);
	}

	@Override
	public boolean complete(String id) {
		Bill bill = this.getById(id);
		// 判断当前结算单状态为：已核对
		if (!bill.getBillStatus().equals(BillStatusEnum.CHECK.name())) {
			throw new ServiceException(ResultCode.BILL_COMPLETE_ERROR);
		}
		// 判断操作人员为后台管理员
		if (!UserContext.getCurrentUser().getRole().equals(UserEnums.MANAGER)) {
			throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
		}
		LambdaUpdateWrapper<Bill> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
		lambdaUpdateWrapper.eq(Bill::getId, id);
		lambdaUpdateWrapper.set(Bill::getPayTime, new Date());
		lambdaUpdateWrapper.set(Bill::getBillStatus, BillStatusEnum.COMPLETE.name());
		return this.update(lambdaUpdateWrapper);
	}

	@Override
	public void download(HttpServletResponse response, String id) {

		Bill bill = this.getById(id);
		ExcelWriter writer = ExcelUtil.getWriterWithSheet("入账订单");
		writer.setSheet("入账订单");
		writer.addHeaderAlias("createTime", "入账时间");
		writer.setColumnWidth(0, 20);
		writer.addHeaderAlias("orderSn", "订单编号");
		writer.setColumnWidth(1, 35);
		writer.addHeaderAlias("storeName", "店铺名称");
		writer.setColumnWidth(2, 20);
		writer.addHeaderAlias("goodsName", "商品名称");
		writer.setColumnWidth(3, 70);
		writer.addHeaderAlias("num", "销售量");
		writer.addHeaderAlias("finalPrice", "订单金额");
		writer.addHeaderAlias("commissionPrice", "平台分佣");
		writer.addHeaderAlias("siteCouponPrice", "平台优惠券");
		writer.setColumnWidth(7, 12);
		writer.addHeaderAlias("distributionRebate", "分销金额");
		writer.addHeaderAlias("pointSettlementPrice", "积分结算金额");
		writer.setColumnWidth(9, 12);
		writer.addHeaderAlias("kanjiaSettlementPrice", "砍价结算金额");
		writer.setColumnWidth(10, 12);
		writer.addHeaderAlias("billPrice", "应结金额");
		writer.setColumnWidth(11, 20);

		List<StoreFlowPayDownloadVO> storeFlowList = storeFlowService.getStoreFlowPayDownloadVO(
				StoreFlowQueryDTO.builder().type(FlowTypeEnum.PAY.name()).bill(bill).build());
		writer.write(storeFlowList, true);

		writer.setSheet("退款订单");
		writer.addHeaderAlias("createTime", "入账时间");
		writer.setColumnWidth(0, 20);
		writer.addHeaderAlias("orderSn", "订单编号");
		writer.setColumnWidth(1, 35);
		writer.addHeaderAlias("refundSn", "售后单号");
		writer.setColumnWidth(2, 35);
		writer.addHeaderAlias("storeName", "店铺名称");
		writer.setColumnWidth(3, 20);
		writer.addHeaderAlias("goodsName", "商品名称");
		writer.setColumnWidth(4, 70);
		writer.addHeaderAlias("num", "销售量");
		writer.addHeaderAlias("finalPrice", "退款金额");
		writer.addHeaderAlias("commissionPrice", "平台分佣");
		writer.addHeaderAlias("siteCouponPrice", "平台优惠券");
		writer.setColumnWidth(8, 12);
		writer.addHeaderAlias("distributionRebate", "分销金额");
		writer.addHeaderAlias("pointSettlementPrice", "积分结算金额");
		writer.setColumnWidth(10, 12);
		writer.addHeaderAlias("kanjiaSettlementPrice", "砍价结算金额");
		writer.setColumnWidth(11, 12);
		writer.addHeaderAlias("billPrice", "结算金额");
		writer.setColumnWidth(12, 20);

		List<StoreFlowRefundDownloadVO> storeFlowRefundDownloadVOList = storeFlowService.getStoreFlowRefundDownloadVO(
				StoreFlowQueryDTO.builder().type(FlowTypeEnum.REFUND.name()).bill(bill).build());
		writer.write(storeFlowRefundDownloadVOList, true);

		ServletOutputStream out = null;
		try {
			// 设置公共属性，列表名称
			response.setContentType("application/vnd.ms-excel;charset=utf-8");
			response.setHeader("Content-Disposition", "attachment;filename="
					+ URLEncoder.encode(bill.getStoreName() + "-" + bill.getSn(), "UTF8") + ".xls");
			out = response.getOutputStream();
			writer.flush(out, true);
		} catch (Exception e) {
			log.error("下载结算单错误", e);
		} finally {
			writer.close();
			IoUtil.close(out);
		}
	}

}
